package com.dashan.backend.datastore;

import static com.dashan.Constants.FULL_PERMISSION;
import static com.dashan.Constants.SEPERATOR;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.jdo.JDOHelper;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.dashan.backend.DashanException;
import com.dashan.backend.XmlSerializable;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

@SuppressWarnings("serial")
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class DsFriend implements Serializable, XmlSerializable {
    @SuppressWarnings("unused")
    @PrimaryKey
    @Persistent
    private Key key;
    
    @Persistent
    private String friendName;
    
    @Persistent
    private Set<Key> groups;
    
    @Persistent
    private Long permissionBits;
    
    @Persistent
    private boolean overrideGroupPermission;
    
    public DsFriend(String userName, String friendName, Set<Key> tags) {
        this.key = buildKey(userName, friendName);
        this.friendName = friendName;
        this.permissionBits = FULL_PERMISSION;
        this.setOverrideGroupPermission(false);
        this.groups = tags;
    }
    
    public DsFriend(String userName, String friendName) {
        this(userName, friendName, new HashSet<Key>());
    }
    
    @Override
    public boolean equals(Object obj) {
        System.out.println(friendName);
        return friendName.compareTo(((DsFriend) obj).getFriendName()) == 0;
    }
    
    public String getFriendName() {
        return friendName;
    }
    
    /**
     * DO NOT use this function directly. Please use
     * FriendManager.addToGroup instead.
     **/
    public void addToGroup(Key group) throws DashanException {
        FriendGroupDao dao = new FriendGroupDao();
        try {
            groups.add(group);
            JDOHelper.makeDirty(this, "groups");
            DsFriendGroup dsGroup = dao.getGroup(group);
            if (dsGroup == null) {
                throw new DashanException("Internal Error, Group not found!" + group.toString());
            } else if (!overrideGroupPermission) {
                permissionBits &= dsGroup.getPermissionBits();
            }
        } finally {
            dao.commit();
        }
    }
    
    /**
     * DO NOT use this function directly. Please use
     * FriendManager.removeFriendFromGroup instead.
     **/
    public void removeFromGroup(Key group) throws DashanException {
        
        // if remove returns false, we don't need recalculate the permission.
        if (!groups.remove(group)) {
            return;
        }
        JDOHelper.makeDirty(this, "groups");
        
        if (!overrideGroupPermission) {            
            permissionBits = getGroupPermission();
        }
    }

    public long getGroupPermission() throws DashanException {
        FriendGroupDao dao = new FriendGroupDao();
        try {
            long newPermissionBits = FULL_PERMISSION;
            for (Key g : groups) {
                DsFriendGroup dsGroup = dao.getGroup(g);
                if (dsGroup == null) {
                    throw new DashanException("Internal Error, Group not found!" + g.toString());
                } else {
                    newPermissionBits &= dsGroup.getPermissionBits();
                }
            }
            return newPermissionBits;
        } finally {
            dao.commit();
        }
    }
    
    public Set<Key> getGroups() {
        return groups;
    }

    public void setPermission(Long permission) {
        this.permissionBits = permission;
    }

    public long getPermission() {
        return permissionBits;
    }
    
    public static Key buildKey(String userName, String friendName) {
        KeyFactory.Builder builder = new KeyFactory.Builder(DsUser.class.getSimpleName(), userName);
        builder.addChild(DsFriend.class.getSimpleName(), friendName);
        return builder.getKey();
    }

    public void setOverrideGroupPermission(boolean overrideGroupPermission) {
        this.overrideGroupPermission = overrideGroupPermission;
    }

    public boolean isOverrideGroupPermission() {
        return overrideGroupPermission;
    }
    
    public Element getXmlElement(Document xmlDoc) {
        Element root = xmlDoc.createElement("friend");
        
        Element ele = null;
        ele = xmlDoc.createElement("friendName");
        ele.appendChild(xmlDoc.createTextNode(getFriendName()));
        root.appendChild(ele);
        ele = xmlDoc.createElement("groups");
        String groups = "";
        for (Key g : getGroups()) {
            groups += g.getName() + SEPERATOR;
        }
        ele.appendChild(xmlDoc.createTextNode(groups));
        root.appendChild(ele);
        return root;
    }
}
